Looping with AI

From Prompts to Loops: Build Your First Self-Correcting AI in 40 Lines

AI Systems 101

Stop Prompting. Start Looping.

Most people are still playing the game on the easy setting. They write one prompt, hit enter, and accept whatever comes back. If it is wrong, they sigh, tweak a few words, and try again — by hand, one shot at a time.

That is prompting. It works until it does not.

The next level is looping: instead of asking once and hoping, you let the model act, check its own work, and try again automatically until the result actually meets your bar.

The difference is not subtle. A single prompt is a coin flip. A loop is a machine that keeps flipping until it lands on heads.

This guide gives you the mental model, the one rule that keeps loops from running away, and a complete first project you can run in about ten minutes.

No framework. No agent library. Just Python, the Claude API, and a while-shaped idea.

```

What a Loop Actually Is

Strip away the buzzwords and every loop is the same four-beat rhythm:

01 Act
02 Check
03 Decide
04 Repeat

The model acts. It writes something, picks something, computes something, or produces a first version.

Then you check the result against a goal.

Then you decide: is it good enough, or do you go again?

If the answer is “go again,” you feed the feedback back in and repeat.

That is it.

That loop is the seed of every “agent,” every research pipeline, every self-healing workflow you have read about. The flashy systems are just this pattern with more steps, more tools, and better stopping logic bolted on.

If you understand the four beats, you understand the whole genre.

The thing that makes it powerful is that the model gets to see its own output and respond to what is actually wrong with it.

A single prompt is the model writing blind.

A loop is the model writing, looking at the result, and correcting it, which is exactly how you would do the task if you cared about getting it right.

Why This Is a Different Sport, Not Just Better Prompting

You can spend a week engineering the perfect prompt to get a model to write “a tweet that is exactly under 280 characters and keeps the core point.”

And it will still blow the limit sometimes, because length is a slippery thing for a language model to feel its way to in a single pass.

No amount of prompt crafting fully fixes that.

It is a blind-shot problem.

A loop fixes it in three lines, because the loop can measure the result and react.

Too long by 40 characters?

Tell the model exactly that and ask again.

The model is not guessing anymore. It is correcting against a real number.

Prompting optimizes the question. Looping optimizes the outcome.

Once you internalize that, you stop trying to write one god-tier prompt and start designing a small system that converges on what you want.

The One Rule: Always Have a Stop Condition

Here is the only way a loop bites you:

It never stops.

The model keeps “improving,” the API keeps charging, and you have built a perpetual motion machine that runs on your credit card.

So the rule, every single time, no exceptions:

Every loop has a MAX_TRIES ceiling — even when it also has a “good enough” exit.

You want two ways out:

  • Success exit The result passed the check. Stop. You won.
  • Safety exit You hit the max number of tries. Stop anyway and return the best you have.

If you only build the success exit, you are one weird edge case away from an infinite loop.

Build both. Always.

The Project: “The 280-Club”

We are going to build a loop that takes any rough idea and turns it into a tweet that fits inside 280 characters while staying punchy and keeping the point.

It is small, genuinely useful, and — crucially — the check is objective.

We can measure character count in plain Python, so the loop is truly self-correcting with zero hand-waving.

You will literally watch it converge.

This is the perfect first loop because it shows the pattern at its cleanest:

  • Act Claude writes a draft.
  • Check Python counts the characters.
  • Decide Under the limit? Done. Over? Tell Claude by how much and loop.
  • Repeat Keep going until it fits or you hit the ceiling.

Setup

You need Python and the Anthropic SDK:

Terminal
pip install anthropic

Then set your API key as an environment variable.

On Mac or Linux:

Mac / Linux
export ANTHROPIC_API_KEY="sk-ant-..."

On Windows PowerShell:

Windows PowerShell
$env:ANTHROPIC_API_KEY="sk-ant-..."

The Code

Create a file called:

Filename
tweet_loop.py

Then paste this in:

Python
import anthropic
```

client = anthropic.Anthropic()  # Reads ANTHROPIC_API_KEY from your environment

MODEL = "claude-sonnet-4-6"
LIMIT = 280
MAX_TRIES = 5

def ask(prompt: str) -> str:
"""One call to Claude. Returns the text of the reply."""
resp = client.messages.create(
model=MODEL,
max_tokens=400,
messages=[
{
"role": "user",
"content": prompt,
}
],
)

```
return resp.content[0].text.strip()
```

idea = """
I spent the weekend learning that the real skill in AI isn't writing
clever prompts — it's building small loops where the model checks its
own work and fixes it automatically. It changed how I think about
everything I build.
"""

draft = ask(
"Turn this idea into one punchy tweet. "
"Return only the tweet.\n\n"
f"{idea}"
)

best_draft = draft

for attempt in range(1, MAX_TRIES + 1):
length = len(draft)

```
print(f"Attempt {attempt} — {length} chars:")
print(draft)
print()

if length <= LIMIT:
    print(f"[ok] Fits in {length} chars after {attempt} attempt(s).")
    break

if len(draft) < len(best_draft):
    best_draft = draft

over = length - LIMIT

draft = ask(
    f"This tweet is {over} characters too long. "
    f"It is {length} characters; the limit is {LIMIT}. "
    f"Rewrite it to be at or under {LIMIT} characters while keeping "
    f"the punch and the core point. "
    f"Return only the tweet.\n\n"
    f"Tweet:\n{draft}"
)
```

else:
print(
f"[!] Couldn't get under {LIMIT} characters in {MAX_TRIES} tries. "
f"Best effort was {len(best_draft)} characters:\n\n"
f"{best_draft}"
)
```

Run it:

Terminal
python tweet_loop.py

That is the whole thing.

Forty-ish lines, and most of them are comments, formatting, and the idea text.

What Is Happening, Beat by Beat

The ask() helper is just “say something to Claude and get text back.”

That is the atom every loop is built from.

The first Claude call creates the first draft.

Then the for loop becomes the engine.

Each pass does four things:

  • It measures the current draft.
  • It checks whether the draft fits.
  • It decides whether to stop.
  • If the draft is too long, it gives Claude specific feedback and asks again.

That specificity is the magic.

We are not re-running the same vague prompt and praying for variance.

We are telling the model the exact gap it needs to close:

“You are 40 characters over.”

Now the model is not guessing.

It is correcting.

That is why the loop converges instead of flailing.

And notice the else attached to the for.

That is a lovely bit of Python.

It runs only if the loop never hits break, which means it only runs if we exhausted all five tries without success.

That is your safety exit, built right in.

What You Will See

Run it, and you will get something like this:

Example Output
Attempt 1 — 291 chars:
```

I spent the weekend realizing the real AI skill isn't clever prompting...

Attempt 2 — 268 chars:
This weekend taught me the real AI skill isn't clever prompts...

[ok] Fits in 268 chars after 2 attempt(s).
```

The first draft overshot.

The loop caught it and told Claude precisely how much to cut.

The second draft landed inside the limit.

You did not touch a thing.

That is a self-correcting system.

And you just built one.

Level Up: Add a Judge

The 280-Club checks one objective thing:

Length.

But a lot of what you care about is not a number.

“Is this actually good?” does not have a len().

The move there is the same loop with a second Claude call as the judge.

Generate → Evaluate → Refine

This is the workhorse of serious AI systems.

Now the loop has two checks:

  • Objective check Does it fit under 280 characters?
  • Subjective check Is it punchy and clear?

The model writes.

Then the model judges.

Then the model improves.

Same loop. More intelligence.

The Upgraded Code

Create a second file called:

Filename
tweet_loop_with_judge.py

Then paste this in:

Python
import anthropic
```

client = anthropic.Anthropic()  # Reads ANTHROPIC_API_KEY from your environment

MODEL = "claude-sonnet-4-6"
LIMIT = 280
MAX_TRIES = 5
TARGET_SCORE = 8

def ask(prompt: str) -> str:
"""One call to Claude. Returns the text of the reply."""
resp = client.messages.create(
model=MODEL,
max_tokens=400,
messages=[
{
"role": "user",
"content": prompt,
}
],
)

```
return resp.content[0].text.strip()
```

def score(tweet: str) -> int:
"""Ask Claude to grade the tweet from 1 to 10."""
reply = ask(
"Rate this tweet from 1 to 10 on punchiness and clarity. "
"Reply with ONLY the number, nothing else.\n\n"
f"{tweet}"
)

```
try:
    return int(reply.split()[0])
except (ValueError, IndexError):
    return 0
```

idea = """
I spent the weekend learning that the real skill in AI isn't writing
clever prompts — it's building small loops where the model checks its
own work and fixes it automatically. It changed how I think about
everything I build.
"""

draft = ask(
"Turn this idea into one punchy tweet. "
f"It must be at or under {LIMIT} characters. "
"Return only the tweet.\n\n"
f"{idea}"
)

best_draft = draft
best_score = 0

for attempt in range(1, MAX_TRIES + 1):
length = len(draft)
fits = length <= LIMIT
grade = score(draft)

```
print(f"Attempt {attempt}: {length} chars, score {grade}/10")
print(draft)
print()

if fits and grade >= TARGET_SCORE:
    print(
        f"[ok] Strong tweet: {grade}/10, "
        f"{length} chars after {attempt} attempt(s)."
    )
    break

if fits and grade > best_score:
    best_draft = draft
    best_score = grade

draft = ask(
    f"Improve this tweet. It must stay at or under {LIMIT} characters. "
    f"It should be sharper, clearer, and punchier. "
    f"Current length: {length}. "
    f"Current score: {grade}/10. "
    f"Target score: {TARGET_SCORE}/10. "
    f"Return only the tweet.\n\n"
    f"Tweet:\n{draft}"
)
```

else:
final_score = score(draft)
final_length = len(draft)

```
if final_length <= LIMIT and final_score > best_score:
    best_draft = draft
    best_score = final_score

print(
    f"[!] Stopped after {MAX_TRIES} tries. "
    f"Best result found: {len(best_draft)} chars, "
    f"score {best_score}/10.\n\n"
    f"{best_draft}"
)

Run it:

Terminal
python tweet_loop_with_judge.py

Now the system is no longer checking only whether the tweet is short enough.

It is checking whether the tweet is good enough.

That is the real jump.

The first version says:

“Did it obey the hard constraint?”

The upgraded version says:

“Did it obey the hard constraint and meet a quality bar?”

That is much closer to how useful AI systems actually work.

A Quick Honesty Note About LLM Judges

An LLM judge is useful, but it is not infallible.

It can be inconsistent.

It can be too generous.

It can miss things a human would catch instantly.

For anything high-stakes, you would tighten the judge.

  • You might give it a rubric.
  • You might show it examples of bad, decent, and excellent outputs.
  • You might ask it to explain the weakness before giving the score.
  • You might use multiple judges and average the results.

But as a first taste of evaluate-and-refine, this is exactly right.

One model playing two roles:

Writer and editor.

That separation is the same idea behind code that fixes its own failing tests, research agents that spot their own gaps, and most of the impressive AI workflows you have seen.

Three Loops to Build Next

Once the pattern clicks, you will see loop-shaped problems everywhere.

Here are three great second projects.

1. The Fact-Checker

Generate an answer.

Then loop:

“What claims here would a skeptic challenge?”

Revise. Check again. Repeat until there are no weak claims left.

The check is not “is this beautiful?” The check is: “Are there unsupported claims?”

Same pattern. Different target.

2. The Constraint Solver

Write something that must satisfy several hard rules at once.

For example:

  • A product name that is one word.
  • Available as a .com.
  • Easy to say out loud.
  • Evokes speed.
  • Does not sound like a medicine.

Single prompts are bad at juggling multiple constraints.

A loop can knock them down one failed check at a time.

3. The Test-and-Fix Loop

This is the coder’s classic:

  • Generate code.
  • Run the tests.
  • Feed any failures back into the model.
  • Try again.
  • Repeat until green.

This is the literal foundation of agentic coding tools.

And you now have everything you need to build a baby version of one.

The Mindset Shift

Here is what changes once you have built a loop or two.

You stop asking:

“What is the perfect prompt?”

And you start asking:

“What is the check?”

Because the check is where the real leverage lives.

If you can measure whether an output is good — even crudely — you can build a loop that drives toward it relentlessly, far past what any single prompt could reach.

Prompting is asking an expert for an answer.

Looping is giving that expert a goal, a way to see their own mistakes, and permission to keep going until it is right.

One of those scales to systems.

The other one is you, by hand, sighing and tweaking words.

Forty lines. Go build the loop.

```